//
// Created by LiuYou on 2021/10/24.
//

#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <cstring>
#include <csignal>
#include <sys/time.h>


static int srcFd;

static volatile bool isLoop{false};


static void releaseResources() {
    close( srcFd );

    const char str[] = "释放文件描述符。\n.";
    write( STDOUT_FILENO, str, sizeof( str ) - 1 );
}


static void alarmHandler(int signal) {
    isLoop = true;
//    alarm( 1 );
}


/*
// getitimer, setitimer - get or set value of an interval timer
 获取或设置间隔计时器的值

   int getitimer(int which, struct itimerval *curr_value);

   // which: 要设置哪个时钟
   // 提供了三种时钟, 即三种计时器。

   int setitimer(int which, const struct itimerval *new_value,
                 struct itimerval *old_value);

DESCRIPTION
       These  system calls provide access to interval timers, that is, timers that initially expire at some point in the future, and (optionally) at regular
       intervals after that.  When a timer expires, a signal is generated for the calling process, and the timer is reset to the specified interval (if  the
       interval is nonzero).
       这些系统调用提供对间隔计时器的访问，即最初在未来某个时间点到期的计时器，并且（可选）在此之后的固定时间间隔内到期。
       当计时器到期时，会为调用进程生成一个信号，并将计时器重置为指定的间隔（如果间隔非零）。

       Three  types of timers—specified via the which argument—are provided, each of which counts against a different clock and generates a different signal
       on timer expiration:
       提供了三种类型的计时器（通过 which 参数指定），每种计时器都针对不同的时钟进行计数，并在计时器到期时生成不同的信号:
       这三种不同的时钟计时器用处不同, 而且不能够互换。

       ITIMER_REAL    This timer counts down in real (i.e., wall clock) time.  At each expiration, a SIGALRM signal is generated.
       ITIMER_REAL      此计时器按实际（即挂钟）时间倒计时(实际时间递减)。在每次到期时(递减为0时)，都会生成一个 SIGALRM 信号。
       这个计时器刚好能代替之前的 alarm(); 函数。

       ITIMER_VIRTUAL This timer counts down against the user-mode CPU time consumed by the process.  (The measurement includes CPU  time  consumed  by  all
                      threads in the process.)  At each expiration, a SIGVTALRM signal is generated.
       ITIMER_VIRTUAL       此计时器根据进程消耗的用户模式 CPU 时间进行倒计时。(即只有当这个进程运行的时候, 它才递减。)
                            （测量包括进程中所有线程消耗的 CPU 时间。）在每次到期时(倒计时为0后)，都会生成一个 SIGVTALRM 信号。

       ITIMER_PROF    This timer counts down against the total (i.e., both user and system) CPU time consumed by the process.  (The measurement includes CPU
                      time consumed by all threads in the process.)  At each expiration, a SIGPROF signal is generated.
       ITIMER_PROF          此计时器根据进程消耗的总（即用户和系统）CPU 时间进行倒计时。(即user+sys的时间。)
                            （测量包括进程中所有线程消耗的 CPU 时间。）在每次到期时(递减为0/倒计时为0后)，都会生成一个 SIGPROF 信号。

       In conjunction with ITIMER_VIRTUAL, this timer can be used to profile user and system CPU time consumed by the process.
       与 ITIMER_VIRTUAL 结合使用，此计时器可用于分析进程消耗的用户和系统 CPU 时间。

       A process has only one of each of the three types of timers.
       一个进程只有三种定时器中的每一种。

       Timer values are defined by the following structures:
       定时器值由以下结构定义:

           struct itimerval {
                struct timeval it_interval; / * Interval for periodic timer(周期性定时器的间隔, 周期) * /
                struct timeval it_value;    / * Time until next expiration(距下一次到期的时间, 即初相位) * /
           };

           struct timeval {
                time_t      tv_sec;         / * seconds(秒) * /
                suseconds_t tv_usec;        / * microseconds(微秒) * /
           };

           1秒等于 1000 毫秒, 1毫秒等于 1000 微秒, 1微秒等于 1000 纳秒。

   getitimer()
       The function getitimer() places the current value of the timer specified by which in the buffer pointed to by curr_value.
       函数 getitimer() 将 which 指定的计时器的当前值放置在 curr_value 指向的缓冲区中。

       The it_value substructure is populated with the amount of time remaining until the next expiration of the specified timer.  This value changes as the
       timer  counts  down, and will be reset to it_interval when the timer expires.  If both fields of it_value are zero, then this timer is currently dis‐
       armed (inactive).
       it_value 子结构填充了指定计时器下一次到期之前剩余的时间量。
       该值随着计时器倒计时而改变，并在计时器到期时重置为 it_interval。
       如果 it_value 的两个字段都为零，则该计时器当前已解除武装（未激活）。

       The it_interval substructure is populated with the timer interval.  If both fields of it_interval are zero, then this is a single-shot  timer  (i.e.,
       it expires just once).
       it_interval 子结构填充有计时器间隔。如果 it_interval 的两个字段都为零，那么这是一个单次定时器（即，它只过期一次）。

   setitimer()
       The  function  setitimer()  arms  or disarms the timer specified by which, by setting the timer to the value specified by new_value.  If old_value is
       non-NULL, the buffer it points to is used to return the previous value of the timer (i.e., the same information that is returned by getitimer()).
       函数 setitimer() 通过将计时器设置为 new_value 指定的值来武装或解除由 which 指定的计时器。
       如果 old_value 为非 NULL，则它指向的缓冲区用于返回计时器的先前值（即，与 getitimer() 返回的信息相同）。

       If either field in new_value.it_value is nonzero, then the  timer  is  armed  to  initially  expire  at  the  specified  time.   If  both  fields  in
       new_value.it_value are zero, then the timer is disarmed.
       如果 new_value.it_value 中的任一字段不为零，则定时器被准备为在指定时间初始到期。如果 new_value.it_value 中的两个字段都为零，则定时器被解除。

       The new_value.it_interval field specifies the new interval for the timer; if both of its subfields are zero, the timer is single-shot.
       new_value.it_interval 字段指定定时器的新间隔: 如果它的两个子字段都为零，则计时器是单次触发的。

RETURN VALUE
       On success, zero is returned.  On error, -1 is returned, and errno is set appropriately.
       成功时，返回零。出错时，返回 -1，并适当设置 errno。

ERRORS
       EFAULT new_value, old_value, or curr_value is not valid a pointer.
       EFAULT new_value、old_value 或 curr_value 不是有效的指针。

       EINVAL which is not one of ITIMER_REAL, ITIMER_VIRTUAL, or ITIMER_PROF; or (since Linux 2.6.22) one of the tv_usec fields in the structure pointed to
              by new_value contains a value outside the range 0 to 999999.
       EINVAL 不是 ITIMER_REAL、ITIMER_VIRTUAL 或 ITIMER_PROF 之一；或（自 Linux 2.6.22 起）new_value 指向的结构中的 tv_usec 字段之一包含 0 到 999999 范围之外的值。


 */
int main(int argc, char** argv) {
    signal( SIGALRM, alarmHandler );
//    alarm( 1 );
    // todo 注意: setitimer();本身就构成了一个时钟周期, 不用再设计 alarm 链这种方式了。
    //  这是非常方便的！
    //  以后就不要使用 alarm(); 了, 使用 setitimer();来代替它。

    itimerval itv{};
    itv.it_interval.tv_sec = 1;
    itv.it_interval.tv_usec = 0;
    itv.it_value.tv_sec = 1;
    itv.it_value.tv_usec = 0;
    // todo 注意: 将第三个参数设置为空即表示不关心之前的时钟计时。
    if (setitimer( ITIMER_REAL, &itv, nullptr ) < 0) {
        perror( "setitimer()" );
        exit( 1 );
    }


    srcFd = open( argv[1], O_RDONLY );
    atexit( releaseResources );


    char buffer[100]{};
    ssize_t readBytes{};
    while (true) {

        while (!isLoop) {
            pause();
        }
        isLoop = false;


        readBytes = read( srcFd, buffer, sizeof( buffer ));
        if (readBytes < 0) {
            perror( "read()" );
            exit( 1 );
        }
        if (readBytes == 0) {
            break;
        }

        ssize_t writeBytes{};
        int writePos{};
        while ((writeBytes = write( STDOUT_FILENO, buffer + writePos, readBytes )) != readBytes) {
            writePos += static_cast<int>(writeBytes);
            readBytes -= writePos;
        }

    }


    return 0;
}
